﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xant.ObjectCloner.Test.Model;
using Xunit;
using Xant.Utils;

namespace Xant.ObjectCloner.Test
{
    public class Tester
    {
        private List<Staff> staffs = new List<Staff>();
        private List<StaffMember> staffMembers = new List<StaffMember>();

        public Tester()
        {
            InitInstance();
        }

        private void InitInstance()
        {
            var shenzhen = new Address() { ZipCode = "518000", FullAddr = "深圳" };
            var guangzhou = new Address() { ZipCode = "510000", FullAddr = "广州" };
            var dept = new Department() { Name = "IT部" };
            var post1 = new Position() { Name = "经理" };
            var post2 = new Position() { Name = "职员" };
            var jayson = new Staff() { Name = "Jayson", StaffNo = "E001", JoinDate = new DateTime(2006, 9, 6) };
            jayson.Addresses.Add(shenzhen);
            jayson.Addresses.Add(guangzhou);
            var sandy = new Staff() { Name = "Sandy", StaffNo = "E002" };
            sandy.Addresses.Add(shenzhen);
            var member1 = new StaffMember() { Department = dept, Position = post1, Staff = jayson, Invalid = false };
            var member2 = new StaffMember() { Department = dept, Position = post2, Staff = sandy, Invalid = false };
            staffs.AddRange(new Staff[] { jayson, sandy });
            staffMembers.AddRange(new StaffMember[]{member1, member2});
        }

        [Fact]
        public void TestDeepClone()
        {
            var member1 = staffMembers.First();
            var member2 = staffMembers.Skip(1).First();
            var clone1 = (StaffMember)member1.Clone();
            var clone2 = (StaffMember)member2.Clone();
            Assert.Equal(member1.Department, member2.Department);//member1和member2所指向的Department属性为同一个Department实例
            Assert.NotEqual(clone1.Department, clone2.Department);//克隆生成的对象其Department属性分别指向两个不同的Department实例
            Assert.NotEqual(clone1, member1.Clone());//每次克隆都将生成新的对象

            Assert.NotEqual(member1.Staff, clone1.Staff);//深拷贝方式生成的克隆对象，属性值所指向的对象也是新的
            Assert.Equal(member1.Staff.Name, clone1.Staff.Name);
            Assert.NotEqual(member1.Staff.Addresses, clone1.Staff.Addresses);
            Assert.NotEqual(member1.Staff.Addresses.First(), clone1.Staff.Addresses.First());
            Assert.Equal(member1.Staff.Addresses.First().FullAddr, clone1.Staff.Addresses.First().FullAddr);
        }

        [Fact]
        public void TestShallowClone()
        {
            var member1 = staffMembers.First();
            var member2 = staffMembers.Skip(1).First();
            var clone1 = (StaffMember)member1.Clone(false);
            var clone2 = (StaffMember)member2.Clone(false);
            Assert.Equal(member1.Staff, clone1.Staff);//浅拷贝方式生成的克隆对象，属性值所指向的还是原对象的引用
            Assert.Equal(member1.Department, clone1.Department);//member1和member2所指向的Department属性为同一个Department实例
            Assert.Equal(clone1.Department, clone2.Department);//浅拷贝方式生成的克隆对象其Department属性指向同一个Department实例
        }

        [Fact]
        public void TestCopy()
        {
            var member1 = staffMembers.First();
            var member2 = staffMembers.Skip(1).First();
            var copy1 = new StaffMember();
            var copy2 = new StaffMember() { Position = member1.Position };
            member1.CopyTo(copy1);
            member2.CopyTo(copy2, "Position");
            Assert.Equal(member1.Staff, copy1.Staff);//浅拷贝方式生成的克隆对象，属性值所指向的还是原对象的引用
            Assert.Equal(member1.Department, copy1.Department);//member1和member2所指向的Department属性为同一个Department实例
            Assert.Equal(copy1.Department, copy2.Department);//浅拷贝方式生成的克隆对象其Department属性指向同一个Department实例
            Assert.Equal(copy2.Position, member1.Position);//复制copy2对象时指定了不复制Position属性，所以copy2对象的Position属性值应该保持初始化时所指定的值(即与member1.Position相同)
            Assert.NotEqual(copy2.Position, member2.Position);
        }

    }

}
